/*
 * Copyright (c) 2018.
 * http://www.ulabcare.com
 */

package com.mt.roll.upms.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mt.roll.core.api.Assert;
import com.mt.roll.core.base.BaseService;
import com.mt.roll.core.dal.entity.SysRole;
import com.mt.roll.core.dal.entity.SysRoleMenu;
import com.mt.roll.core.dal.entity.SysUserRole;
import com.mt.roll.core.dal.service.*;
import com.mt.roll.core.enums.WhetherEnum;
import com.mt.roll.core.errorcode.ApiErrorCode;
import com.mt.roll.core.params.EnabledParam;
import com.mt.roll.core.params.IdListParam;
import com.mt.roll.core.params.IdParam;
import com.mt.roll.core.vo.IdListVo;
import com.mt.roll.core.vo.IdVo;
import com.mt.roll.core.vo.PageVo;
import com.mt.roll.core.vo.R;
import com.mt.roll.upms.mapper.RoleMapper;
import com.mt.roll.upms.params.SysRoleParam;
import com.mt.roll.upms.params.SysRoleQueryParam;
import com.mt.roll.upms.params.UserRoleParam;
import com.mt.roll.upms.service.RoleService;
import com.mt.roll.upms.vo.SysRoleVo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 角色服务实现类
 * <p>
 * //TODO 需要完善删除角色逻辑
 * </p>
 *
 * @author jiff
 * @date 2018/11/23
 * @since 1.0
 */
@Service
@Transactional
public class RoleServiceImpl extends BaseService implements RoleService {
    private final SysUserServiceBiz sysUserServiceBiz;
    private final SysOrgServiceBiz sysOrgServiceBiz;
    private final SysRoleServiceBiz sysRoleServiceBiz;
    private final SysUserRoleServiceBiz sysUserRoleServiceBiz;
    private final SysRoleMenuServiceBiz sysRoleMenuServiceBiz;
    private final RoleMapper roleMapper;

    @Autowired
    public RoleServiceImpl(SysUserServiceBiz sysUserServiceBiz, SysOrgServiceBiz sysOrgServiceBiz, SysRoleServiceBiz sysRoleServiceBiz, SysUserRoleServiceBiz sysUserRoleServiceBiz, SysRoleMenuServiceBiz sysRoleMenuServiceBiz, RoleMapper roleMapper) {
        this.sysUserServiceBiz = sysUserServiceBiz;
        this.sysOrgServiceBiz = sysOrgServiceBiz;
        this.sysRoleServiceBiz = sysRoleServiceBiz;
        this.sysUserRoleServiceBiz = sysUserRoleServiceBiz;
        this.sysRoleMenuServiceBiz = sysRoleMenuServiceBiz;
        this.roleMapper = roleMapper;
    }

    /**
     * 获取角色
     *
     * @param idParam 主键参数
     * @return 角色
     */
    @Override
    public R<SysRoleVo> get(IdParam idParam) {
        SysRole sysRole = sysRoleServiceBiz.getById(idParam.getId());
        Assert.notNull("角色不存在", sysRole);
        SysRoleVo sysRoleVo = SysRoleVo.builder().build();
        BeanUtils.copyProperties(sysRole, sysRoleVo);
        return successful(sysRoleVo);
    }

    /**
     * 获取角色列表
     *
     * @param sysRoleQueryParam 角色查询参数
     * @return 角色列表
     */
    @Override
    public R<List<SysRoleVo>> list(SysRoleQueryParam sysRoleQueryParam) {
        QueryWrapper<SysRole> wrapper = new QueryWrapper<>();
        wrapper.eq(ObjectUtils.isNotNull(sysRoleQueryParam.getCategory()), SysRole.CATEGORY, sysRoleQueryParam.getCategory())
                .eq(ObjectUtils.isNotNull(sysRoleQueryParam.getEnabled()), SysRole.ENABLED, sysRoleQueryParam.getEnabled())
                .like(StringUtils.isNotBlank(sysRoleQueryParam.getCode()), SysRole.CODE, sysRoleQueryParam.getCode())
                .like(StringUtils.isNotBlank(sysRoleQueryParam.getName()), SysRole.NAME, sysRoleQueryParam.getName());
        List<SysRole> sysRoles = sysRoleServiceBiz.list(wrapper);
        List<SysRoleVo> sysRoleVos = com.mt.roll.core.utils.BeanUtils.copyList(sysRoles, SysRoleVo.class);
        return successful(sysRoleVos);
    }

    /**
     * 获取角色分页列表
     *
     * @param sysRoleQueryParam 角色查询参数
     * @return 角色分页列表
     */
    @Override
    public R<PageVo<SysRoleVo>> page(SysRoleQueryParam sysRoleQueryParam) {
        QueryWrapper<SysRole> wrapper = new QueryWrapper<>();
        wrapper.eq(ObjectUtils.isNotNull(sysRoleQueryParam.getCategory()), SysRole.CATEGORY, sysRoleQueryParam.getCategory())
                .eq(ObjectUtils.isNotNull(sysRoleQueryParam.getEnabled()), SysRole.ENABLED, sysRoleQueryParam.getEnabled())
                .like(StringUtils.isNotBlank(sysRoleQueryParam.getCode()), SysRole.CODE, sysRoleQueryParam.getCode())
                .like(StringUtils.isNotBlank(sysRoleQueryParam.getName()), SysRole.NAME, sysRoleQueryParam.getName());
        IPage<SysRole> page = sysRoleServiceBiz.page(new Page<>(sysRoleQueryParam.getCurrent(), sysRoleQueryParam.getSize()), wrapper);
        return successful(new PageVo<>(page, SysRoleVo.class));
    }

    /**
     * 新增角色
     *
     * @param sysRoleParam 角色参数
     * @return 主键
     */
    @Override
    public R<IdVo> add(SysRoleParam sysRoleParam) {
        QueryWrapper<SysRole> wrapper = new QueryWrapper<>();
        wrapper.eq(SysRole.CODE, sysRoleParam.getCode());
        Assert.eqZero(sysRoleServiceBiz.count(wrapper), "角色编码已经存在");
        SysRole sysRole = new SysRole();
        BeanUtils.copyProperties(sysRoleParam, sysRole);
        sysRole.setManagerFlag(WhetherEnum.NO.getValue());
        sysRole.setPreset(WhetherEnum.NO.getValue());
        setCommonField(sysRole);
        sysRoleServiceBiz.save(sysRole);
        return successful(IdVo.builder().id(sysRole.getId()).build());
    }

    /**
     * 更新角色
     *
     * @param sysRoleParam 角色参数
     * @return 主键
     */
    @Override
    public R<IdVo> update(SysRoleParam sysRoleParam) {
        SysRole sysRole = sysRoleServiceBiz.getById(sysRoleParam.getId());
        //修改角色编码需要检验新编码是否已存在
        if (!sysRole.getCode().equals(sysRoleParam.getCode())) {
            QueryWrapper<SysRole> wrapper = new QueryWrapper<>();
            wrapper.eq(SysRole.CODE, sysRoleParam.getCode());
            Assert.eqZero(sysRoleServiceBiz.count(wrapper), "角色编码已经存在");
        }
        //修改角色分类需要检验角色是否已经关联菜单
        if (!sysRole.getCategory().equals(sysRoleParam.getCategory())) {
            QueryWrapper<SysRoleMenu> wrapper = new QueryWrapper<>();
            wrapper.eq(SysRoleMenu.ROLE_ID, sysRoleParam.getId());
            Assert.eqZero(sysRoleMenuServiceBiz.count(wrapper), "角色已关联菜单信息，不许修改角色分类");
        }
        SysRole updateSysRole = new SysRole();
        BeanUtils.copyProperties(sysRoleParam, updateSysRole);
        setUpdateCommonField(updateSysRole);
        sysRoleServiceBiz.updateById(updateSysRole);
        return successful(IdVo.builder().id(sysRole.getId()).build());
    }

    /**
     * 启用停用
     *
     * @param enabledParam 启停参数
     * @return 主键
     */
    @Override
    public R<IdVo> enabled(EnabledParam enabledParam) {
        SysRole sysRole = sysRoleServiceBiz.getById(enabledParam.getId());
        if (sysRole == null) {
            return failed("角色不存在");
        }
        if (!enabledParam.getEnabled().equals(sysRole.getEnabled())) {
            SysRole updateSysRole = new SysRole().setId(sysRole.getId());
            updateSysRole.setEnabled(enabledParam.getEnabled());
            setUpdateCommonField(updateSysRole);
            sysRoleServiceBiz.updateById(updateSysRole);
        }
        return successful(IdVo.builder().id(sysRole.getId()).build());
    }

    /**
     * 删除角色
     *
     * @param idParam 主键参数
     * @return 主键
     */
    @Override
    public R<IdVo> delete(IdParam idParam) {
        SysRole sysRole = sysRoleServiceBiz.getById(idParam.getId());
        if (sysRole == null) {
            return failed("角色不存在");
        }
        //检查角色下是否还有用户
        QueryWrapper<SysUserRole> wrapper = new QueryWrapper();
        wrapper.eq(SysUserRole.ROLE_ID, sysRole.getId());
        Assert.eqZero(sysUserRoleServiceBiz.count(wrapper), "该角色下还有用户");
        //删除角色菜单关系
        sysRoleMenuServiceBiz.remove(new QueryWrapper<SysRoleMenu>().eq(SysRoleMenu.ROLE_ID, idParam.getId()));
        //使用更新方式删除，需要把code设置为历史code（后面跟随机数）
        SysRole updateSysRole = new SysRole().setId(sysRole.getId());
        updateSysRole.setCode(sysRole.getCode() + "_" + RandomUtils.nextInt());
        updateSysRole.setValid(WhetherEnum.NO.getValue());
        setUpdateCommonField(updateSysRole);
        sysRoleServiceBiz.updateById(updateSysRole);
        //更新时逻辑删除字段没有更新，需要再调用一次删除操作
        sysRoleServiceBiz.removeById(updateSysRole.getId());
        return successful(IdVo.builder().id(sysRole.getId()).build());
    }

    /**
     * 批量删除角色
     *
     * @param idListParam 主键列表参数
     * @return 主键列表
     */
    @Override
    public R<IdListVo> delete(IdListParam idListParam) {
        return null;
    }

    /**
     * 保存用户角色
     *
     * @param userRoleParam 用户角色参数
     * @return 主键列表
     */
    @Override
    public R<IdListVo> saveUserRole(UserRoleParam userRoleParam) {
        Long userId = userRoleParam.getUserId();
        Assert.notNull(ApiErrorCode.USER_NON_EXISTENT, sysUserServiceBiz.getById(userId));
        //检查设置的角色是否都存在
        List<Long> roleIds = userRoleParam.getRoleIds();
        if (CollectionUtils.isNotEmpty(roleIds)) {
            Collection<SysRole> roles = sysRoleServiceBiz.listByIds(roleIds);
            if (roleIds.size() != roles.size()) {
                return failed("角色不存在");
            }
        }
        //先删除原有的用户角色关系
        sysUserRoleServiceBiz.remove(new QueryWrapper<SysUserRole>().eq(SysUserRole.USER_ID, userId));
        if (CollectionUtils.isNotEmpty(roleIds)) {
            List<SysUserRole> userRoles = roleIds.stream().map(roleId -> setCommonField(new SysUserRole().setUserId(userId).setRoleId(roleId)))
                    .collect(Collectors.toList());
            sysUserRoleServiceBiz.saveBatch(userRoles);
            return successful(IdListVo.builder().ids(userRoles.stream().map(SysUserRole::getId).collect(Collectors.toList())).build());
        }

        return successful(null);
    }

    /**
     * 获取用户角色列表
     *
     * @param idParam 主键参数
     * @return 角色列表
     */
    @Override
    public R<List<SysRoleVo>> listByUser(IdParam idParam) {
        List<SysRoleVo> sysRoleVos = roleMapper.listByUser(idParam.getId());
        return successful(sysRoleVos);
    }
}
